import React, { Component } from "react";
import { Button, TextInput } from "react-desktop/macOs";
import "./Page.scss";
import { remote, App, BrowserWindow, WebContents, shell } from "electron";
import { StFile } from "../../class/StFile";
import { FolderChild } from "../FolderChild/FolderChild";
import { Menu } from "../Menu/Menu";
import * as path from "path";
import * as fs from "fs";
import ReactDOM from "react-dom";
import * as childProcess from "child_process";
import { getParentUntil } from "../../func/dom";
declare const __static: string;
export namespace Page {
    export interface State {
        nowDir: string;
        fileList: string[];
        childElms: JSX.Element[];
        dirInputValue: string;
        isErrorDir: boolean,
        selectedItems: string[],
        showMenu: boolean;
        menuTop: number;
        menuLeft: number;
    }
}

export class Page extends Component<any, Page.State> {
    readonly state = {
        nowDir: '/Users/chiyuxinyi/Documents/procedures',
        fileList: [],
        dirInputValue: '/Users/chiyuxinyi/Documents/procedures',
        isErrorDir: false,
        selectedItems: [],
        childElms: [],
        showMenu: false,
        menuTop: 0,
        menuLeft: 0,
    };
    readonly app: App = remote.app;
    readonly win: BrowserWindow = remote.getCurrentWindow();
    readonly page: WebContents = remote.getCurrentWebContents();
    readonly dirHistory: string[] = [];
    constructor(props: Readonly<{}> = {}) {
        super(props);
        console.log('aaa');
        this.dirHistory = [this.state.nowDir];
    }
    public render() {
        return <div className="page" style={{ backgroundImage: `url("file://${__static}/img/bg.jpg")` }}>
            <div className="now-dir">
                <div className="absolute-rows">
                    <div className="first-row">
                        <TextInput
                            onChange={this.whenChangeDir.bind(this)}
                            value={this.state.dirInputValue}
                            onEnter={this.whenDirInputEnter.bind(this)}
                            className={this.state.isErrorDir ? 'error-dir' : ''}
                        ></TextInput>
                    </div>
                    <div className="second-row">
                        <Button color="blue" onClick={this.toParenDir.bind(this)}>上一级</Button>
                        <Button color="blue" onClick={this.toPrevDir.bind(this)}>上一步</Button>
                        <Button color="blue" onClick={this.toNextDir.bind(this)}>下一步</Button>
                    </div>
                </div>
                <div className="folder-children-list" onContextMenu={this.whenPopMenu.bind(this)} >
                    <div className="list-titles">
                        <div className="base-name">名称</div>
                        <div className="mtime">修改日期</div>
                        <div className="ctime">创建日期</div>
                        <div className="size">大小</div>
                    </div>
                    <div className="list-body">{this.state.childElms}</div>
                </div>
                {this.getMenu()}
            </div>
        </div>
    }
    public toPrevDir() {
        let nowDirIndex = this.getHistoryIndex(this.state.nowDir);
        nowDirIndex--;
        if (nowDirIndex < 0) {
            return;
        }
        this.setState({
            selectedItems: [],
            showMenu: false,
        });
        this.jumpToDirByIndex(nowDirIndex);
    }
    public toNextDir() {
        let nowDirIndex = this.getHistoryIndex(this.state.nowDir);
        nowDirIndex++;
        if (nowDirIndex >= this.dirHistory.length) {
            return;
        }
        this.setState({
            selectedItems: [],
            showMenu: false,
        });
        this.jumpToDirByIndex(nowDirIndex);
    }
    public jumpToDirByIndex(dirIndex: number) {
        let nextDir = this.dirHistory[dirIndex];
        this.jumpToDir(nextDir);
    }
    public getMenu() {
        if (this.state.showMenu) {
            return <Menu
                top={this.state.menuTop}
                left={this.state.menuLeft}
                wantToRefresh={this.whenMenuRefresh.bind(this)}
                openWith={this.openWith.bind(this)}
                createNewFile={this.createNewFile.bind(this)}
                selectedFile={this.state.selectedItems[0]}
                renameFile={this.renameFile.bind(this)}
                delFile={this.delFiles.bind(this)}
                addFolder={this.addFolder.bind(this)}
            ></Menu>;
        }
        return null;
    }
    protected renameFile() {
        this.closeMenu();
        let file = this.state.selectedItems[0];
        let elm = document.body.querySelector(`.folder-child[data-filename="${file}"]`);;
        if (elm) {
            let baseNameElm = elm.querySelector('.base-name .short-name') as HTMLElement;
            if (baseNameElm) {
                baseNameElm.contentEditable = "true";
            }
        }
    }
    protected delFile(file: string): Promise<void> {
        return new Promise((resolve, reject) => {
            fs.unlink(file, (err) => {
                if (err) {
                    reject(err);
                } else {
                    console.log(`delete ${file} success`);
                    let selectItems = this.state.selectedItems.filter(value => value != file);
                    this.setState({
                        selectedItems: selectItems
                    }, () => {
                        this.updateChildElms();
                    });
                    resolve();
                }
            });
        });
    }
    protected getDelFilesPromise(files: string[]): Promise<void[]> {
        let promises: Promise<void>[] = [];
        files.forEach(file => {
            let promise = this.delFile(file);
            promises.push(promise);
        });
        return Promise.all(promises);
    }
    protected delFiles() {
        let files = this.state.selectedItems;
        this.getDelFilesPromise(files).then(() => {
            this.whenMenuRefresh();
        }).catch(err => {
            console.error(err);
            this.whenMenuRefresh();
        });
    }
    public getNewFileIndexName(filePrefix: string, ext: string = '', index: number = 0) {
        let fullName: string;
        let list = this.state.fileList;
        if (ext) {
            ext = '.' + ext;
        }
        if (index) {
            fullName = `${filePrefix}-${index}${ext}`;
        } else {
            fullName = filePrefix + ext
        }
        fullName = path.join(this.state.nowDir, fullName);
        if (list.indexOf(fullName) <= 0) {
            return fullName;
        }
        index++;
        return this.getNewFileIndexName(filePrefix, ext, index);
    }

    public createNewFile(fileType: string) {
        let newFileName = this.getNewFileIndexName('template', fileType);
        let filer = new StFile(newFileName);
        filer.create().then(() => {
            this.whenMenuRefresh();
        }).catch(err => {
            console.error(err);
            this.whenMenuRefresh();
        });
    }
    public openWith(editor: 'code' | 'finder' | 'default') {
        let items = this.state.selectedItems;
        let item: string = items[0];
        if (!item) {
            item = this.state.nowDir;
        }
        if (editor === 'default') {
            shell.openItem(item);
            this.closeMenu();
            return;
        }
        let cmd = editor === 'code' ? '/Applications/Visual\\ Studio\\ Code.app/Contents/Resources/app/bin/code' : 'open';
        if (!item) {
            item = this.state.nowDir;
        }
        this.closeMenu();
        childProcess.exec(`${cmd} ${item}`, (err, stdout, stderr) => {
            if (err) {
                console.error(err);
            } else {
                console.log(stdout);
            }
        });
    }
    public closeMenu(): Promise<void> {
        return new Promise((resolve, reject) => {
            this.setState({
                showMenu: false
            }, () => {
                resolve();
            });
        });
    }
    public whenMenuRefresh() {
        this.jumpToDir(this.state.nowDir);
        this.setState({
            showMenu: false,
        });
    }
    public toParenDir() {
        let dir = path.join(this.state.nowDir, "..");
        let filer = new StFile(dir);
        this.setState({
            selectedItems: []
        });
        filer.exists().then(exists => {
            if (exists) {
                this.jumpToDir(dir);
            }
        });
    }
    public updateFileList(fileList: string[]): this {
        this.setState({
            fileList,
        }, () => {
            this.updateChildElms();
        });
        return this;
    }
    public whenPopMenu() {
        let mouseEvent = event as MouseEvent;
        let top = mouseEvent.clientY - 10;
        let left = mouseEvent.clientX;
        let onElm = getParentUntil(event.target as HTMLElement, '.folder-child');
        if (onElm) {
            let selectedFile = this.state.selectedItems[0];
            if (!selectedFile) {
                selectedFile = onElm.getAttribute("data-filename");
                this.selectItem(selectedFile);
                this.showMenu(top, left);
                return;
            }
        }
        this.showMenu(top, left);
    }
    public showMenu(top: number = 0, left: number = 0) {
        this.setState({
            showMenu: true,
            menuTop: top,
            menuLeft: left
        });
    }
    public updateChildElms(): this {
        ///
        let fullNames = this.state.fileList;
        let childElms = fullNames.map((fullName, index) => {
            return this.getFolderChild(fullName, index);
        });
        this.setState({
            childElms,
        });
        return this;
    }
    public getFolderChild(fullName: string, index: number) {
        let timeStamp = (new Date()).getTime();
        return <FolderChild
            key={index + '@' + timeStamp}
            selectedItems={this.state.selectedItems}
            fullName={fullName}
            onClick={this.whenClickFolderChild.bind(this)}
            onDoubleClick={this.whenDbClickFolderChild.bind(this)}
            whenRename={this.rename.bind(this)}
        ></FolderChild>;
    }
    public baseName(fullPath: string) {
        return path.basename(fullPath);
    }
    public close(): this {
        this.win.close();
        return this;
    }
    protected whenDirInputEnter() {
        let dir = this.state.dirInputValue;
        let filer = new StFile(dir);
        filer.getState().then(stat => {
            if (stat.isDirectory()) {
                this.setState({
                    nowDir: dir,
                    isErrorDir: false
                });
                this.getList();
            } else {
                this.setState({
                    isErrorDir: true
                })
            }
        }).catch(err => {
            this.setState({
                isErrorDir: true
            });
        });
    }
    protected whenChangeDir(evt: Event) {
        let input = evt.target as HTMLInputElement;
        this.setState({
            dirInputValue: input.value
        });
    }
    public updateDir(dir: string) {
        this.getList();
    }
    public async getList() {
        let nowDir = this.state.nowDir;
        let filer = new StFile(nowDir);
        let files = await filer.list();
        let fileList = [];
        let excludeFiles = [
            ".DS_Store",
            ".DocumentRevisions-V100",
            ".HFS+ Private Directory Data",
            ".Trashes",
            ".Trash",
            ".file",
            ".fseventsd",
            ".vol",
            ".Spotlight-V100",
            ".PKInstallSandboxManager-SystemSoftware",
            ".OSInstallerMessages",
            "installer.failurerequests"
        ];
        files.forEach((value, index) => {
            if (excludeFiles.indexOf(value) < 0) {
                let fileFullName = path.join(nowDir, value);
                fileList.push(fileFullName);
            }
        });
        this.updateFileList(fileList);
    }
    public isSelectIt(fileFullName: string): boolean {
        if (this.state.selectedItems.indexOf(fileFullName) >= 0) {
            return true;
        }
        return false;
    }
    public whenDbClickFolderChild(arg: string, isDir: boolean, evt: Event) {
        if (isDir) {
            this.setState({
                showMenu: false,
            });
            this.jumpToDir(arg);
        }
    }
    protected addToDirHistory(dir: string) {
        if (this.getHistoryIndex(dir) < 0) {
            this.dirHistory.push(dir);
        }
    }
    protected getHistoryIndex(dir: string) {
        return this.dirHistory.indexOf(dir);
    }
    public jumpToDir(dir: string): void {
        this.addToDirHistory(dir);
        this.setState({
            nowDir: dir,
            dirInputValue: dir,
            selectedItems: [],
        }, () => {
            this.getList();
        });
    }
    public whenClickFolderChild(fullName: string, evt: Event) {
        if (this.isSelectIt(fullName)) {
            return;
        }
        this.selectItem(fullName);
    }
    public selectItem(fullName: string) {
        this.setState({
            selectedItems: [fullName],
        }, () => {
            console.log(this.state.selectedItems);
            this.updateChildElms();
        });
    }
    public componentDidMount() {
        this.getList();
        this.listenEvent();
    }
    public componentWillMount() {
    }
    protected listenEvent() {
        window.addEventListener('keyup', (event) => {
            if (event.keyCode === 13) {
                this.listenEnterUp();
            }
        });
    }
    public rename(file: string, elm: HTMLElement) {
        let originDir = path.dirname(file);
        let nameElm = elm.querySelector('.base-name .short-name') as HTMLElement;
        let newName = nameElm.innerText.replace(" ", "\ ").trim();
        fs.rename(file, path.join(originDir, newName), (err) => {
            if (err) {
                console.error(err);
            } else {
                nameElm.contentEditable = "false";
                this.whenMenuRefresh();
            }
        });
    }
    protected listenEnterUp() {
        let editableNameElm = document.body.querySelector('.folder-child .base-name .short-name[contenteditable="true"]') as HTMLElement;
        if (editableNameElm) {
            let folderChild = getParentUntil(editableNameElm, '.folder-child');
            let originName = folderChild.getAttribute("data-filename");
            this.rename(originName, folderChild);
        }
    }
    public install(appDiv: HTMLElement): this {
        ReactDOM.render(<Page></Page>, appDiv);
        return this;
    }
    public addFolder() {
        let fileName = this.getNewFileIndexName('new-floder');
        fs.mkdir(fileName, (err) => {
            if (err) {
                console.error(err);
                return;
            }
            this.whenMenuRefresh();
        });
    }
}
